package com.ysh.smartplatform.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ysh.smartplatform.cache.CategoryCache;
import com.ysh.smartplatform.cache.DeviceCache;
import com.ysh.smartplatform.constans.ResultCode;
import com.ysh.smartplatform.event.CategoryChangeEvent;
import com.ysh.smartplatform.event.DeviceChangeEvent;
import com.ysh.smartplatform.event.DeviceColorEvent;
import com.ysh.smartplatform.event.DeviceCommandEvent;
import com.ysh.smartplatform.exceptions.AddDataException;
import com.ysh.smartplatform.exceptions.FindDataException;
import com.ysh.smartplatform.mapper.CategoryMapper;
import com.ysh.smartplatform.mapper.DeviceMapper;
import com.ysh.smartplatform.pojo.BaseUser;
import com.ysh.smartplatform.pojo.SysCategory;
import com.ysh.smartplatform.pojo.SysDevice;
import com.ysh.smartplatform.pojo.SysUserInfo;
import com.ysh.smartplatform.service.DeviceService;
import com.ysh.smartplatform.service.SceneService;
import com.ysh.smartplatform.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.DeleteMapping;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 袁胜虎 on 2022/9/8 20:15
 */
@Service
@Transactional
public class DeviceServiceImpl implements DeviceService {
    private CategoryMapper categoryMapper;

    @Autowired
    public void setCategoryMapper(CategoryMapper categoryMapper) {
        this.categoryMapper = categoryMapper;
    }


    private ObjectMapper objectMapper;

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    private CategoryCache categoryCache;

    @Autowired
    public void setCategoryCache(CategoryCache categoryCache) {
        this.categoryCache = categoryCache;
    }

    private DeviceCache deviceCache;

    @Autowired
    public void setDeviceCache(DeviceCache deviceCache) {
        this.deviceCache = deviceCache;
    }

    private ApplicationContext applicationContext;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    private SceneService sceneService;

    @Autowired
    public void setSceneService(SceneService sceneService) {
        this.sceneService = sceneService;
    }

    private DeviceMapper deviceMapper;

    @Autowired
    public void setDeviceMapper(DeviceMapper deviceMapper) {
        this.deviceMapper = deviceMapper;
    }

    @Override
    public void addDevice(SysDevice sysDevice) {
        //我们需要获取到当前登录的用户
        BaseUser userInfo = SecurityUtils.getLoginUser();
        sysDevice.setBindUserId(userInfo.getuId());

        //TODO 判断分类是不是存在
        //如果传递了场景id,我们还得判断当前的场景id属于这个用户
        Long sceneId = sysDevice.getSceneId();
        if (sceneId != null && (-1 > sceneId || 0 == sceneId)) {
                //传递了id不符合要求
                throw new AddDataException("场景不存在", ResultCode.DATA_NOT_EXIST);
            }else if (sceneId!=null&&sceneId>0){
            //传递了一个场景id,但是这个场景不一定属于谁
            //判断是否属于当前用户
            sceneService.getSceneById(sceneId);
        }
        //这个设备可能已经被绑定到了其它人身上
        SysDevice device = findByDeviceId(sysDevice.getDeviceId());
        Assert.isTrue(device==null||device.getBindUserId().equals(sysDevice.getBindUserId()),()->{
            throw new AddDataException("设备已经别绑定",ResultCode.DEVICE_ALREADY_BIND);
        });
        if (device==null){
            //执行绑定操作
            deviceMapper.bindDevice(sysDevice);
        }
    }
    @Override
    public SysDevice findByDeviceId(String id) {
        Assert.notNull(id,()->{
            throw  new FindDataException("未找到参数",ResultCode.PARAM_CONTENT_EMPTY);
        });
        return deviceMapper.findByDeviceId(id);
    }

    @Override
    public void deleteDeviceById(String id) {
        deviceMapper.deleteDevice(id);
        Assert.notNull(id,()->{
            throw  new FindDataException("未找到参数",ResultCode.PARAM_CONTENT_EMPTY);
        });
        applicationContext.publishEvent(new DeviceChangeEvent());
    }

    @Override
    public void updateDevice(SysDevice sysDevice) {
        deviceMapper.updateDevice(sysDevice);
        Assert.notNull(sysDevice,()->{
            throw  new FindDataException("数据中含有空的参数",ResultCode.PARAM_CONTENT_EMPTY);
        });
        applicationContext.publishEvent(new DeviceChangeEvent());
    }

    @Override
    public List<SysDevice> findAllDevice() {
        List<SysDevice> deviceList = deviceCache.getDeviceList();
        return deviceList;
    }

    @Override
    public SysDevice findById(String id) {
        SysDevice sysDevice = deviceCache.get(id);
        Assert.notNull(sysDevice,()->{
            throw  new FindDataException("设备不存在",ResultCode.DATA_NOT_EXIST);
        });
        return sysDevice;
    }

    @Override
    public int updateDeviceStatus(String deviceId, int status) {
        return deviceMapper.updateDeviceStatus(deviceId,status);
    }
    @Override
    public void sendCommand(String deviceId, String command) {
        //command实际上就是open,close等
        //根据设备的id找到设备的会话,然后把我们的command当做内容发过去
        //我们可以发送一个事件过去,让websocket自己处理
        //我们需要将命令转成实际的数据,到底怎么转换,取决于我们实际定义的情况
        //TODO 根据设备的id查询到设备的分类id,然后根据分类id查询到命令,然后根据传递过来的命令的名字来获取到真正的命令,然后给设备发送过
        Map map = new HashMap<>();
//        categoryMapper.findByCommend(categoryId);
        try {
            Long categoryId = deviceMapper.findByCategoryId(deviceId);
            SysCategory category = categoryCache.get(categoryId);
            map =  objectMapper.readValue(category.getTxCommand(),Map.class);
            //根据传递过来的命令key获取到对应的命令数据
            if(map.get(command)instanceof Map){
                Map cMap = (Map) map.get(command);
                if (cMap != null){
                    Integer type = (Integer) cMap.get("type");
                    if (type != null){
                        //电源控制,将真正的命令获取到后通过事件发送出去
                        applicationContext.publishEvent(new DeviceCommandEvent(deviceId,(String)cMap.get("command")));
                    }else if (type == 2){
                        //变色控制
                        applicationContext.publishEvent(new DeviceColorEvent(deviceId,(String)cMap.get("command")));
                    }
                }
                //更新设备控制时间
                updateControlTime(deviceId);
                return;
            }

//            applicationContext.publishEvent(new DeviceCommandEvent(deviceId,""+map.get(command)));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
//        throw new AddDataException("没有启动设备",ResultCode.DATA_NOT_EXIST);
    }

    @Override
    public void updateControlTime(String deviceId) {
        CompletableFuture.runAsync(()->{
            SysDevice device = new SysDevice();
            device.setDeviceId(deviceId);
            device.setLastControlTime(new Date());
            deviceMapper.updateByPrimaryKeySelective(device);
        });
    }
}
